#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>

// 如果我们不想等待子进程，并且我们还想让子进程退出之后，自动释放僵尸子进程,怎么办???
int main()
{
    // os直接设置的忽略与我们直接手动设置忽略的区别: 手动设置忽略能让子进程自动释放
    signal(SIGCHLD, SIG_IGN); 

    if(fork() == 0)
    {
        std::cout << "child: " << getpid() << std::endl;
        sleep(5);
        exit(0);
    }

    while(true)
    {
        std::cout << "parent: " << getpid() << " 执行任务..." << std::endl;
        sleep(1);
    }
}

// // 当子进程退出发送17号信号时,父进程进行回收

// std::vector<pid_t> pids;

// int childProcSize = 0;

// // void recycle(int signum)
// // {
// //     std::cout << " 开始信号: " << signum << " pid: " << getpid() << std::endl;

// //     for (int i = 0; i < childProcSize; i++)
// //     {
// //         pid_t id=0;

// //         if((id=waitpid(-1,nullptr,WNOHANG))>0)
// //         {
// //             std::cout<<" 回收子进程成功: "<<id<<std::endl;
// //             childProcSize--;
// //         }
// //         else
// //         {
// //             std::cout<<" 回收子进程失败: "<<id<<std::endl;
// //         }
// //     }

// //     // pid_t id=0;

// //     // while(true)
// //     // {
// //     //     if((id=waitpid(-1,nullptr,WNOHANG))>0)
// //     //     {
// //     //         std::cout<<" 回收子进程成功: "<<id<<std::endl;
// //     //         break;
// //     //     }
// //     //     else
// //     //     {
// //     //         std::cout<<" 回收子进程失败: "<<id<<std::endl;
// //     //     }
// //     // }

// //     std::cout << " 结束信号: " << signum << " pid: " << getpid() << std::endl;
// // }

// void recycle(int signum)
// {
//     std::cout<<" 开始信号: "<<signum<<" pid: "<<getpid()<<std::endl;

//     for(int i=0;i<static_cast<int>(pids.size());i++)
//     {   
//         pid_t id=0;

//         if((id=waitpid(pids[i],nullptr,WNOHANG))>0)
//         {
//             std::cout<<" 回收子进程成功: "<<pids[i]<<" id: "<<id<<std::endl;
//         }
//         else // ret==0||ret==-1 子进程已经没了返回-1 子进程还没有变僵尸进程返回0
//         {
//             std::cout<<" 回收子进程失败: "<<pids[i]<<" id "<<id<<std::endl;
//         }
//     }
//     std::cout<<" 结束信号: "<<signum<<" pid: "<<getpid()<<std::endl;
// }

// int main()
// {
//     for (int i = 0; i < 10; i++)
//     {
//         pid_t id = fork();
//         if (id == 0)
//         {
//             std::cout << i << " child: " << getpid() << std::endl;

//             while (true)
//             {
//             }
//         }
//         else if (id > 0)
//         {
//             pids.push_back(id);
//             childProcSize++;
//         }
//     }

//     signal(SIGCHLD, recycle);

//     while (true)
//     {
//     }

//     return 0;
// }

// // SIGCHLD:当子进程退出时,会给父进程发送17号信号
// void CatchSignal(int signum)
// {
//     std::cout<<" child process exit: "<<signum<<" fater: "<<getpid()<<std::endl;
// }

// int main()
// {
//     signal(SIGCHLD,CatchSignal);

//     pid_t id=fork();
//     if(id==0)
//     {
//         std::cout<<"child: "<<getpid()<<std::endl;
//         sleep(10);
//         exit(0);
//     }

//     // 等子进程退出
//     while(true)
//     {
//         sleep(1);
//     }

//     return 0;
// }

// // 了解volatile关键字

// // 每次访问flag时,都需要到内存中访问
// volatile bool flag = true;

// void CatchSignal(int signum)
// {
//     (void)signum;
//     std::cout <<"change flag: "<<flag;

//     flag = false;

//     std::cout << "->" << flag << std::endl;
// }

// int main(int, char **, char **)
// {
//     signal(SIGINT, CatchSignal);

//     while (flag)
//     {}

//     std::cout << "退出: " << flag << std::endl;

//     return 0;
// }

// // 了解sigaction接口的使用以及struct sigaction类型中某些字段的意义

// // struct sigaction
// // {
// //     void (*sa_handler)(int); // 指定与signum相关联的动作，可以是默认动作的SIG_DFL，忽略该信号的SIG_IGN，或者指向信号处理函数的指针。
// //     void (*sa_sigaction)(int, siginfo_t *, void *);
// //     sigset_t sa_mask; // 指定在信号执行期间应该阻塞的信号掩码,默认执行当前信号被阻塞
// //     int sa_flags;
// //     void (*sa_restorer)(void);
// // };

// static void ShowPending(sigset_t *set)
// {
//     for(int i=1;i<=31;i++)
//     {
//         std::cout<<sigismember(set,i);
//     }
//     std::cout<<std::endl;
// }

// void handler(int signum)
// {
//     std::cout<<"开始执行信号: "<<signum<<std::endl;
//     // 验证在收到信号之后,正在执行该信号的动作,不能被其他信号打断
//     // 其他信号应该处于阻塞,只有当该当前信号的动作处理完成,才能将其他信号去阻塞
//     // 从而保证信号动作的连贯性
//     for(int i=0;i<15;i++)
//     {
//         sigset_t set;
//         sigpending(&set);

//         ShowPending(&set);

//         sleep(1);
//     }
//     std::cout<<"结束执行信号: "<<signum<<std::endl;
// }

// int main()
// {
//     std::cout<<getpid()<<std::endl;

//     // 设置内核数据类型
//     struct sigaction act;
//     struct sigaction oact;

//     act.sa_handler=&handler;
//     act.sa_flags=0;
//     sigemptyset(&(act.sa_mask));

//     sigaddset(&(act.sa_mask),3);
//     sigaddset(&(act.sa_mask),4);
//     sigaddset(&(act.sa_mask),5);
//     sigaddset(&(act.sa_mask),6);
//     sigaddset(&(act.sa_mask),7);

//     // 检查和改变信号动作
//     // int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
//     // 设置特定信号的处理动作
//     sigaction(SIGINT,&act,&oact);

//     // signal捕获信号时,会在指定信号执行期间阻塞当前执行信号吗???
//     // signal(SIGINT,handler); // 默认都会阻塞当前执行信号,等当前信号执行完,又会进行执行

//     // 执行任务...
//     while(true) sleep(1);

//     return 0;
// }